﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Globalization;
using System.IO;

namespace Draco.Commons.Reflection
{
    /// <summary>
    /// 反射工厂
    /// </summary>
    public class ReflectFactory
    {
        /// <summary>
        /// 获取程序集
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <returns></returns>
        public static Assembly GetAssembly(AssemblyName assemblyName)
        {
            if (assemblyName!=null)
            {
                //先从当前域查找
                Assembly[] allass = System.AppDomain.CurrentDomain.GetAssemblies();
                for (int i = 0; i < allass.Length; i++)
                {
                    if (allass[i].FullName == assemblyName.FullName)
                    {
                        return allass[i];
                    }
                }
                //没有找到就加载
                try
                {
                    //反射程序集获取程序集和类对象
                    Assembly assb = Assembly.Load(assemblyName);
                    return assb;
                }
                catch(Exception e)
                {
                    throw e;
                }
            }
            return null;
        }
        /// <summary>
        /// 获取程序集
        /// </summary>
        /// <param name="assemblyPath">程序集的物理路径</param>
        /// <returns></returns>
        public static Assembly LoadAssemblyFile(string filePath)
        {
            /**
             * 程序集路径@"D:\MyWorkSpace\Draco2005\WebTest\bin\TestDll.dll"
             * */
            if (!String.IsNullOrEmpty(filePath) && File.Exists(filePath))
            {
                //反射程序集获取程序集和类对象
                return Assembly.LoadFile(filePath);
            }
            return null;
        }

        /// <summary>
        /// 获取类型
        /// </summary>
        /// <param name="assmbly"></param>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public static Type GetType(Assembly assmbly,string typeName)
        {
            if (assmbly != null && !String.IsNullOrEmpty(typeName))
            {
                return assmbly.GetType(typeName);
            }
            return null;
        }
        /// <summary>
        /// 获取类型
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public static Type GetType(AssemblyName assemblyName, string typeName)
        {
            Assembly assembly = GetAssembly(assemblyName);
            return GetType(assembly,typeName);
        }

        /// <summary>
        /// 获取对象
        /// </summary>
        /// <param name="type"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static Object GetObject(Type type, params object[] args)
        {
            if (type != null)
            {
                Assembly assmbly = type.Assembly;
                return GetObject(assmbly, type, args);
            }
            return null;
        }
        /// <summary>
        /// 获取对象
        /// </summary>
        /// <param name="assmbly"></param>
        /// <param name="type"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        private static Object GetObject(Assembly assmbly,Type type,params object[] args)
        {
            if (assmbly != null && type != null)
            {
                object instance = assmbly.CreateInstance(type.FullName, false, BindingFlags.CreateInstance,
                                            Type.DefaultBinder, args, System.Globalization.CultureInfo.CurrentCulture, null);
                return instance;
            }
            return null;
        }

        /// <summary>
        /// 获取方法
        /// </summary>
        /// <param name="type"></param>
        /// <param name="methodName"></param>
        /// <returns></returns>
        public static MethodInfo GetMethod(Type type,string methodName)
        {
            if (type != null && !String.IsNullOrEmpty(methodName))
            {
                return type.GetMethod(methodName);
            }
            return null;
        }
        /// <summary>
        /// 获取方法
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <param name="typeName"></param>
        /// <param name="methodName"></param>
        /// <returns></returns>
        public static MethodInfo GetMethod(AssemblyName assemblyName,string typeName, string methodName)
        {
            Type type = GetType(assemblyName, typeName);
            return GetMethod(type, methodName);
        }

        /// <summary>
        /// 把方法包装为委托
        /// </summary>
        /// <param name="delegateType"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        public static Delegate WrapMethod(Type delegateType, MethodInfo method)
        {
            return WrapMethod(delegateType, null, method);
        }
        /// <summary>
        /// 把方法包装为委托
        /// </summary>
        /// <param name="delegateType">委托类型</param>
        /// <param name="Instance">声明method方法的类型实例</param>
        /// <param name="method">方法</param>
        /// <returns></returns>
        public static Delegate WrapMethod(Type delegateType,Object Instance, MethodInfo method)
        {
            if (method.IsStatic)
                return Delegate.CreateDelegate(delegateType, method);

            if(Instance==null)
                Instance = GetObject(method.ReflectedType.Assembly, method.ReflectedType, null);//无参构造
            return Delegate.CreateDelegate(delegateType, Instance, method);
        }

        /// <summary>
        /// 调用方法
        /// </summary>
        /// <param name="method"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static Object InvokeMethod(MethodInfo method,params object[] args)
        {
            if (method != null)
            {
                Object instance=null;
                if (!method.IsStatic)
                {
                    instance = GetObject(method.ReflectedType.Assembly, method.ReflectedType);
                }
                object[] oargs = TryMatchParameter(method,args);
                return method.Invoke(instance, BindingFlags.InvokeMethod, Type.DefaultBinder, oargs, CultureInfo.CurrentCulture);
            }
            return null;
        }

        /// <summary>
        /// 尝试匹配参数个数
        /// </summary>
        /// <param name="method">方法</param>
        /// <param name="args">参数数组</param>
        /// <returns></returns>
        private static object[] TryMatchParameter(MethodInfo method, object[] args)
        {
            ParameterInfo[] Paras = method.GetParameters();
            if (Paras == null || Paras.Length == 0)         //不需要参数
                return null;
            if (args != null && args.Length == Paras.Length)//完全匹配
                return args;
            else
            {
                int aLength = args == null ? 0 : args.Length;//待用的参数长度
                object[] Args = new object[Paras.Length];   //以实际参数个数为准
                for (int i = 0; i < Args.Length; i++)
                {
                    Args[i] = i < aLength ? args[i] : new object();
                }
                return Args;
            }
        }
    }
}
